package com.smart.web3j;

import java.io.File;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;

import org.bouncycastle.util.encoders.Hex;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Bip39Wallet;
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.MnemonicUtils;
import org.web3j.crypto.Wallet;
import org.web3j.crypto.WalletFile;
import org.web3j.crypto.WalletUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.smart.web3j.model.CreateWalletReponse;
import com.smart.web3j.model.CreateWalletRequest;
import com.smart.web3j.model.KeystoreWalletRequest;
import com.smart.web3j.model.Mnemonic2PrivateKeyRequest;
import com.smart.web3j.model.MnemonicWalletRequest;
import com.smart.web3j.model.PrivateKey2MneMonicRequest;
import com.smart.web3j.model.PrivateKeyWalletRequest;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class WalletService {
	

	public CreateWalletReponse createWallet(CreateWalletRequest request)
			throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, CipherException, IOException {
		String tempdir = System.getProperty("java.io.tmpdir");

		CreateWalletReponse response = new CreateWalletReponse();
		Bip39Wallet bip39Wallet = WalletUtils.generateBip39Wallet(request.getMnemonicPassword(), new File(tempdir));
		Credentials credentials = WalletUtils.loadBip39Credentials(request.getMnemonicPassword(), bip39Wallet.getMnemonic());
		response.setMnemonicString(bip39Wallet.getMnemonic());

		response.setAddress(credentials.getAddress());
		response.setPublicKey(credentials.getEcKeyPair().getPublicKey().toString(16));
		response.setPrivateKey(credentials.getEcKeyPair().getPrivateKey().toString(16));

		WalletFile walletFile = Wallet.createStandard(request.getKeyStorePassword(), credentials.getEcKeyPair());
		String keystore = JSON.toJSONString(walletFile);
		response.setKeystore(JSONObject.parseObject(keystore));
		log.info("response:{}", JSON.toJSONString(response));

		return response;
	}

	public CreateWalletReponse keystoreWallet(KeystoreWalletRequest request) throws IOException, CipherException {
		Credentials credentials = WalletUtils.loadJsonCredentials(request.getKeystorePassword(), request.getKeystore().toJSONString());

		CreateWalletReponse response = new CreateWalletReponse();
		response.setKeystore(request.getKeystore());
		response.setAddress(credentials.getAddress());
		response.setPublicKey(credentials.getEcKeyPair().getPublicKey().toString(16));
		response.setPrivateKey(credentials.getEcKeyPair().getPrivateKey().toString(16));
		return response;
	}

	public CreateWalletReponse mnemonicWallet(MnemonicWalletRequest request) throws CipherException {
		CreateWalletReponse response = new CreateWalletReponse();
		Credentials credentials = WalletUtils.loadBip39Credentials(request.getMnemonicPassword(), request.getMnemonicString());

		response.setAddress(credentials.getAddress());
		response.setPublicKey(credentials.getEcKeyPair().getPublicKey().toString(16));
		response.setPrivateKey(credentials.getEcKeyPair().getPrivateKey().toString(16));

		WalletFile walletFile = Wallet.createStandard(request.getKeyStorePassword(), credentials.getEcKeyPair());
		String keystore = JSON.toJSONString(walletFile);
		response.setKeystore(JSONObject.parseObject(keystore));
		return response;
	}

	public CreateWalletReponse privateKeyWallet(PrivateKeyWalletRequest request) throws CipherException {
		CreateWalletReponse response = new CreateWalletReponse();

		ECKeyPair eCKeyPair = ECKeyPair.create(Hex.decode(request.getPrivateKey()));
		WalletFile walletFile = Wallet.createStandard(request.getKeyStorePassword(), eCKeyPair);

		response.setAddress(walletFile.getAddress());
		response.setPublicKey(eCKeyPair.getPublicKey().toString(16));
		response.setPrivateKey(eCKeyPair.getPrivateKey().toString(16));

		String keystore = JSON.toJSONString(walletFile);
		response.setKeystore(JSONObject.parseObject(keystore));
		return response;
	}
	
	public String privateKey2Mnemonic(PrivateKey2MneMonicRequest request) {
		byte[] tempPrivateKey = Hex.decode(request.getPrivateKey());
		return MnemonicUtils.generateMnemonic(tempPrivateKey);
	}
	
	public String mnemonic2PrivateKey(Mnemonic2PrivateKeyRequest request) {
		byte[] tempPrivateKey = MnemonicUtils.generateEntropy(request.getMnemonicString());
		return Hex.toHexString(tempPrivateKey);
	}
}
